package com.iotcomm.server;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iotcomm.listener.MessageListener;
import com.iotcomm.model.UserInfo;
import com.iotcomm.protocol.Message;
import com.iotcomm.protocol.MessageCodec;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import javafx.application.Platform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * 聊天服务器主类
 * 负责启动Netty服务器，管理用户连接，处理消息转发
 */
public class ChatServer implements MessageListener {
    private static final Logger logger = LoggerFactory.getLogger(ChatServer.class);
    
    private final int port;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel serverChannel;
    
    // 用户管理
    private final Map<String, UserInfo> users = new ConcurrentHashMap<>(); // channelId -> UserInfo
    private final Map<String, String> usernameToChannelId = new ConcurrentHashMap<>(); // username -> channelId
    
    // 心跳检测
    private final ScheduledExecutorService heartbeatExecutor = Executors.newSingleThreadScheduledExecutor();
    private static final int HEARTBEAT_TIMEOUT = 20; // 20秒超时
    
    // 回调函数
    private Consumer<List<UserInfo>> userListUpdateCallback;
    private Consumer<String> serverStatusCallback;
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 构造函数
     * @param port 服务器端口
     */
    public ChatServer(int port) {
        this.port = port;
    }
    
    /**
     * 启动服务器
     */
    public void start() {
        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup();
        
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            // 添加消息编解码器
                            pipeline.addLast(new MessageCodec());
                            // 添加业务处理器
                            pipeline.addLast(new ServerHandler(ChatServer.this));
                        }
                    });
            
            // 绑定端口并启动服务器
            ChannelFuture future = bootstrap.bind(port).sync();
            serverChannel = future.channel();
            
            logger.info("聊天服务器启动成功，端口: {}", port);
            updateServerStatus("服务器运行中 - 端口: " + port);
            
            // 启动心跳检测
            startHeartbeatCheck();
            
        } catch (Exception e) {
            logger.error("服务器启动失败", e);
            updateServerStatus("服务器启动失败: " + e.getMessage());
            stop();
        }
    }
    
    /**
     * 停止服务器
     */
    public void stop() {
        try {
            // 停止心跳检测
            heartbeatExecutor.shutdown();
            
            // 关闭服务器通道
            if (serverChannel != null) {
                serverChannel.close().sync();
            }
            
            // 关闭事件循环组
            if (bossGroup != null) {
                bossGroup.shutdownGracefully();
            }
            if (workerGroup != null) {
                workerGroup.shutdownGracefully();
            }
            
            logger.info("聊天服务器已停止");
            updateServerStatus("服务器已停止");
            
        } catch (Exception e) {
            logger.error("停止服务器时发生错误", e);
        }
    }
    
    /**
     * 启动心跳检测
     */
    private void startHeartbeatCheck() {
        heartbeatExecutor.scheduleAtFixedRate(() -> {
            try {
                List<String> timeoutChannels = new ArrayList<>();
                
                // 检查超时的用户
                for (UserInfo userInfo : users.values()) {
                    if (userInfo.isTimeout(HEARTBEAT_TIMEOUT)) {
                        timeoutChannels.add(userInfo.getChannelId());
                        logger.info("用户 {} 心跳超时，准备断开连接", userInfo.getUsername());
                    }
                }
                
                // 断开超时的连接
                for (String channelId : timeoutChannels) {
                    ServerHandler.getChannels().stream()
                            .filter(channel -> channel.id().asShortText().equals(channelId))
                            .findFirst()
                            .ifPresent(Channel::close);
                }
                
            } catch (Exception e) {
                logger.error("心跳检测异常", e);
            }
        }, 10, 10, TimeUnit.SECONDS);
    }
    
    @Override
    public void onMessageReceived(Message message, String channelId) {
        try {
            // 更新用户活跃时间和统计信息
            UserInfo userInfo = users.get(channelId);
            if (userInfo != null) {
                userInfo.updateLastActiveTime();
                userInfo.incrementMessageCount();
                userInfo.addTraffic(message.toJson().getBytes().length);
            }
            
            switch (message.getMessageType()) {
                case Message.LOGIN:
                    handleLogin(message, channelId);
                    break;
                case Message.LOGOUT:
                    handleLogout(channelId);
                    break;
                case Message.PRIVATE_CHAT:
                    handlePrivateChat(message, channelId);
                    break;
                case Message.BROADCAST:
                    handleBroadcast(message, channelId);
                    break;
                case Message.HEARTBEAT:
                    handleHeartbeat(message, channelId);
                    break;
                default:
                    logger.warn("未知消息类型: {}", message.getMessageType());
            }
            
            // 更新用户列表
            updateUserList();
            
        } catch (Exception e) {
            logger.error("处理消息时发生错误", e);
        }
    }
    
    /**
     * 处理登录请求
     */
    private void handleLogin(Message message, String channelId) {
        String username = message.getSender();
        
        // 检查用户名是否已存在
        if (usernameToChannelId.containsKey(username)) {
            // 发送错误响应
            Message errorMsg = new Message(Message.ERROR, "SERVER", username, "用户名已存在");
            ServerHandler.sendToChannel(channelId, errorMsg);
            return;
        }

        // 将返回的内容包装为Optional
        Optional<InetSocketAddress> inetSocketAddress = ServerHandler.getChannels().stream()
                .filter(channel -> channel.id().asShortText().equals(channelId))
                .findFirst()
                .map(channel -> (InetSocketAddress) channel.remoteAddress());

        // 获取客户端IP地址
        String ipAddress = inetSocketAddress.map(ip -> ip.getAddress().getHostAddress()).orElse("未知");
        // 获取客户端端口
        int clientPort = inetSocketAddress.map(InetSocketAddress::getPort).orElse(0);

        // 创建用户信息
        UserInfo userInfo = new UserInfo(username, channelId, ipAddress, clientPort);
        users.put(channelId, userInfo);
        usernameToChannelId.put(username, channelId);
        
        logger.info("用户 {} 登录成功，IP: {} 端口: {}", username, ipAddress, clientPort);
        
        // 发送登录成功响应
        Message response = new Message(Message.LOGIN_RESPONSE, "SERVER", username, "登录成功");
        ServerHandler.sendToChannel(channelId, response);
        
        // 发送当前在线用户列表
        sendUserList(channelId);
        
        // 广播用户列表更新给所有用户
        broadcastUserList();
        
        // 广播用户上线消息
        Message broadcastMsg = new Message(Message.BROADCAST, "SERVER", "ALL", username + " 加入了聊天室");
        ServerHandler.broadcastExclude(broadcastMsg, channelId);
    }
    
    /**
     * 处理登出请求
     */
    private void handleLogout(String channelId) {
        UserInfo userInfo = users.remove(channelId);
        if (userInfo != null) {
            usernameToChannelId.remove(userInfo.getUsername());
            logger.info("用户 {} 登出", userInfo.getUsername());
            
            // 广播用户下线消息
            Message broadcastMsg = new Message(Message.BROADCAST, "SERVER", "ALL", 
                    userInfo.getUsername() + " 离开了聊天室");
            ServerHandler.broadcast(broadcastMsg);
        }
    }
    
    /**
     * 处理私聊消息
     */
    private void handlePrivateChat(Message message, String channelId) {
        String targetUsername = message.getReceiver();
        String targetChannelId = usernameToChannelId.get(targetUsername);
        
        if (targetChannelId != null) {
            // 转发消息给目标用户
            ServerHandler.sendToChannel(targetChannelId, message);
            
            // 不再向发送者回显消息，因为发送者在发送时已经在本地显示了
            
            logger.debug("转发私聊消息: {} -> {}", message.getSender(), targetUsername);
        } else {
            // 目标用户不在线，发送错误消息
            Message errorMsg = new Message(Message.ERROR, "SERVER", message.getSender(), 
                    "用户 " + targetUsername + " 不在线");
            ServerHandler.sendToChannel(channelId, errorMsg);
        }
    }
    
    /**
     * 处理广播消息
     */
    private void handleBroadcast(Message message, String channelId) {
        // 广播消息给所有用户（包括发送者）
        ServerHandler.broadcast(message);
        logger.debug("广播消息: {}", message.getSender());
    }
    
    /**
     * 处理心跳消息
     */
    private void handleHeartbeat(Message message, String channelId) {
        // 心跳响应
        Message heartbeatResponse = new Message(Message.HEARTBEAT, "SERVER", message.getSender(), "");
        ServerHandler.sendToChannel(channelId, heartbeatResponse);
    }
    
    /**
     * 发送用户列表给指定客户端
     */
    private void sendUserList(String channelId) {
        try {
            List<String> usernames = new ArrayList<>(usernameToChannelId.keySet());
            String userListJson = objectMapper.writeValueAsString(usernames);
            
            Message userListMsg = new Message(Message.USER_LIST, "SERVER", null, userListJson);
            ServerHandler.sendToChannel(channelId, userListMsg);
        } catch (JsonProcessingException e) {
            logger.error("序列化用户列表失败", e);
        }
    }
    
    /**
     * 广播用户列表更新
     */
    private void broadcastUserList() {
        try {
            List<String> usernames = new ArrayList<>(usernameToChannelId.keySet());
            String userListJson = objectMapper.writeValueAsString(usernames);
            
            Message userListMsg = new Message(Message.USER_LIST, "SERVER", null, userListJson);
            ServerHandler.broadcast(userListMsg);
        } catch (JsonProcessingException e) {
            logger.error("序列化用户列表失败", e);
        }
    }
    
    @Override
    public void onClientConnected(String channelId) {
        logger.debug("客户端连接: {}", channelId);
    }
    
    @Override
    public void onClientDisconnected(String channelId, String username) {
        UserInfo userInfo = users.remove(channelId);
        if (userInfo != null) {
            usernameToChannelId.remove(userInfo.getUsername());
            logger.info("用户 {} 断开连接", userInfo.getUsername());
            
            // 广播用户下线消息
            Message broadcastMsg = new Message(Message.BROADCAST, "SERVER", "ALL", 
                    userInfo.getUsername() + " 离开了聊天室");
            ServerHandler.broadcast(broadcastMsg);
            
            // 广播用户列表更新
            broadcastUserList();
        }
        
        updateUserList();
    }
    
    @Override
    public void onConnectionError(String channelId, Throwable cause) {
        logger.error("连接错误: {}", channelId, cause);
    }
    
    /**
     * 更新用户列表（通知UI）
     */
    private void updateUserList() {
        if (userListUpdateCallback != null) {
            Platform.runLater(() -> {
                List<UserInfo> userList = new ArrayList<>(users.values());
                userListUpdateCallback.accept(userList);
            });
        }
    }
    
    /**
     * 更新服务器状态（通知UI）
     */
    private void updateServerStatus(String status) {
        if (serverStatusCallback != null) {
            Platform.runLater(() -> serverStatusCallback.accept(status));
        }
    }
    
    // Getter和Setter方法
    public void setUserListUpdateCallback(Consumer<List<UserInfo>> callback) {
        this.userListUpdateCallback = callback;
    }
    
    public void setServerStatusCallback(Consumer<String> callback) {
        this.serverStatusCallback = callback;
    }
    
    public int getOnlineUserCount() {
        return users.size();
    }
    
    public List<UserInfo> getOnlineUsers() {
        return new ArrayList<>(users.values());
    }
}